package com.yoke.controller.digging;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.yoke.common.EncodeFileUtil;
import com.yoke.common.JsonMessage;
import com.yoke.common.QiNiuFile;
import com.yoke.common.base.DiggingBaseControl;
import com.yoke.system.SystemBean;
import com.yoke.system.log.LogType;
import com.yoke.system.log.SystemLog;
import com.yoke.util.*;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by jiangzeyin on 2017/6/28.
 */
@Controller
@RequestMapping("digging")
public class DiggingControl extends DiggingBaseControl {

    private static final String UAG = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";

    @RequestMapping(value = "index.html", produces = MediaType.TEXT_HTML_VALUE)
    public String index() {
        return "digging/index";
    }

    @RequestMapping(value = "bank_to.html", produces = MediaType.TEXT_HTML_VALUE)
    public String bank_to(String tag, String status) throws UnsupportedEncodingException {
        String result = checkTag(tag, status);
        if (result != null)
            return result;
        request.setAttribute("tag", tag);
        request.setAttribute("status", status);
        return "digging/edit_1";
    }

    private String checkTag(String tag, String status) throws UnsupportedEncodingException {
        if (!StringUtil.IsEmpty(status)) {
            if (!"tf".equals(status) && !"sh".equals(status))
                return dore("status 不正确", tag, status);
        }
        if (!StringUtil.IsEmpty(tag)) {
            try {
                String path = EncryptUtil.decrypt(tag);
                File file = new File(path);
                if (!file.exists()) {
                    return dore("tag 不正确", tag, status);
                }
                if ("tf".equals(status)) {
                    File tf = new File(file.getParentFile(), "index_tf.html");
                    if (tf.exists()) {
                        return dore("已经存在投放页啦", tag, status);
                    }
                } else if ("sh".equals(status)) {
                    File sh = new File(file.getParentFile(), "index_sh.html");
                    if (sh.exists()) {
                        return dore("已经存在审核页啦", tag, status);
                    }
                }
            } catch (Exception e) {
                SystemLog.LOG(LogType.CONTROL_ERROR).error("判断tag", e);
                return dore("tag 异常" + e.getMessage(), tag, status);
            }
        }
        return null;
    }


    @RequestMapping(value = "do", method = RequestMethod.POST, produces = MediaType.TEXT_HTML_VALUE)
    public String doUrl(String url,
                        boolean weixin,
                        boolean js,
                        boolean tongji, String tag, String status,
                        boolean h404, String quality, boolean ys) throws UnsupportedEncodingException {
        float quality_ = StringUtil.parseFloat(quality);
        if (quality_ == 0.0F) {
            quality_ = 0.7f;
        } else if ((quality_ != 100.0F) && (quality_ <= 0.0F || quality_ >= 1.0F)) {
            quality_ = 0.7f;
        }
        if (!ys)
            quality_ = 100.0F;
        if (StringUtil.IsEmpty(url)) {
            return dore("请输入链接", tag, status);
        }
        String result = checkTag(tag, status);
        if (result != null)
            return result;
        File tempParent = new File(String.format("%s/temp/%s", getBootPath(), userName));
        if (!FileUtil.deleteDir(tempParent)) {
            SystemLog.LOG().info("清理临时文件失败：" + tempParent.getPath());
        }
        try {
            Connection connection = Jsoup.connect(url);
            Document document = connection.timeout(10 * 1000).userAgent(UAG).get();
            String doMain = getDoMain();
            {
                // 处理编码
                Elements metas = document.getElementsByTag("meta");
                metas.forEach(element -> {
                    String httpEquiv = element.attr("http-equiv");
                    if ("Content-Type".equalsIgnoreCase(httpEquiv)) {
                        element.attr("content", "text/html; charset=utf-8");
                    }
                });
                Elements scripts = document.getElementsByTag("script");
                if (js) {
                    scripts.remove();
                } else {
                    // 下载js
                    scripts.forEach(element -> {
                        String src = element.attr("src").trim();
                        if (!StringUtil.IsEmpty(src)) {
                            if (tongji) { // 判断统计代码
                                if (src.contains("cnzz.com"))
                                    element.remove();
                            }
                            String jsUrl = convertUrl(src, url);
                            String mName = Md5Util.getMd5(jsUrl);
                            String fileName = String.format("%s/js/%s.js", tempParent.getPath(), mName);
                            boolean flag;
                            try {
                                flag = httpDownload(jsUrl, fileName, h404);
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                            // 清理404 标签
                            if (!flag && h404) {
                                element.remove();
                                return;
                            }
                            if (!flag) {
                                throw new RuntimeException("下载文件失败：" + jsUrl);
                            }
                            // 强制为utf-8
                            try {
                                fileName = EncodeFileUtil.convert(new File(fileName), "UTF-8");
                            } catch (IOException e) {
                                SystemLog.LOG(LogType.CONTROL_ERROR).error("转换文件编码失败：" + fileName, e);
                                throw new RuntimeException("转换文件编码失败" + e.getMessage());
                            }
                            String md5;
                            try {
                                md5 = QiNiuFile.doUploadFile(fileName);
                            } catch (Exception e) {
                                SystemLog.LOG(LogType.CONTROL_ERROR).error("扒取失败：" + jsUrl, e);
                                throw new RuntimeException(e.getMessage());
                            }
                            src = FileUtil.ClearPath(String.format("%s/%s", doMain, md5));
                            element.attr("src", src);
                        }
                    });
                }
            }
            {
                Elements link = document.getElementsByTag("link");
                link.forEach(element -> {
                    String rel = element.attr("rel");
                    if (!StringUtil.IsEmpty(rel) && !"stylesheet".equalsIgnoreCase(rel))
                        return;
                    String href = element.attr("href").trim();
                    String hrefUrl = convertUrl(href, url);
                    String mName = Md5Util.getMd5(hrefUrl);
                    String fileName = String.format("%s/css/%s.css", tempParent.getPath(), mName);
                    boolean flag;
                    try {
                        flag = httpDownload(hrefUrl, fileName, h404);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                    // 清理404 标签
                    if (!flag && h404) {
                        element.remove();
                        return;
                    }
                    if (!flag) {
                        throw new RuntimeException("下载文件失败：" + hrefUrl);
                    }
                    String md5;
                    try {
                        md5 = QiNiuFile.doUploadFile(fileName);
                    } catch (Exception e) {
                        SystemLog.LOG(LogType.CONTROL_ERROR).error("扒取失败" + hrefUrl, e);
                        throw new RuntimeException(e.getMessage());
                    }
                    href = FileUtil.ClearPath(String.format("%s/%s", doMain, md5));
                    element.attr("href", href);
                });
            }
            {
                Elements imgs = document.getElementsByTag("img");
                float finalQuality_ = quality_;
                imgs.forEach(element -> {
                    String src;
                    String attrName = weixin ? "data-src" : "src";
                    src = element.attr(attrName).trim();
                    if (weixin)
                        element.removeAttr("data-src");
                    if (StringUtil.IsEmpty(src))
                        return;
                    String srcUrl = convertUrl(src, url);
                    String mName = Md5Util.getMd5(srcUrl);
                    String fileName = String.format("%s/img/%s", tempParent.getPath(), mName);
                    boolean flag;
                    try {
                        flag = httpDownload(srcUrl, fileName, h404);
                    } catch (Exception e) {
                        SystemLog.LOG(LogType.CONTROL_ERROR).error("扒取失败", e);
                        throw new RuntimeException(e);
                    }
                    // 清理404 标签
                    if (!flag && h404) {
                        element.remove();
                        return;
                    }
                    if (!flag) {
                        throw new RuntimeException("下载文件失败：" + srcUrl);
                    }
                    String md5;
                    try {
                        md5 = QiNiuFile.doUploadFile(fileName, finalQuality_);
                    } catch (Exception e) {
                        SystemLog.LOG(LogType.CONTROL_ERROR).error("扒取失败:" + srcUrl, e);
                        throw new RuntimeException(e.getMessage());
                    }
                    // String trueName = getTrueName(mName);
                    src = FileUtil.ClearPath(String.format("%s/%s", doMain, md5));
                    element.attr("src", src);
                });
            }
            String time = String.valueOf(System.currentTimeMillis());
            FileUtil.writeFile(String.format("%s/html/%s.html", tempParent.getPath(), time), document.toString());
            request.setAttribute("time", time);
            request.setAttribute("tag", tag);
            request.setAttribute("status", status);
            return "digging/edit_1";
        } catch (Exception e) {
            SystemLog.LOG(LogType.CONTROL_ERROR).error("扒取失败：" + url, e);
            return dore("获取异常:" + e.getMessage(), tag, status);
        }
    }

    private String dore(String tip, String tag, String status) throws UnsupportedEncodingException {
        String url = "redirect:index.html?tip=" + UrlDecode.getURLEncode(tip);
        if (!StringUtil.IsEmpty(tag))
            url += "&tag=" + tag;
        if (!StringUtil.IsEmpty(status))
            url += "&status=" + status;
        return url;
    }

    @RequestMapping(value = "getContext.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public String save_weixin(String time) {
        time = convertFilePath(time);
        File tempParent = new File(String.format("%s/temp/%s", getBootPath(), userName));
        try {
            File file = new File(String.format("%s/html/%s.html", tempParent.getPath(), time));
            if (!file.exists())
                return JsonMessage.getString(400, "获取失败");
            String context = FileUtil.readToString(file);
            if (!file.delete()) {
                SystemLog.LOG().info("删除文件失败：" + file.getPath());
            }
            return JsonMessage.getString(200, "", context);
        } catch (IOException e) {
            SystemLog.LOG(LogType.CONTROL_ERROR).error("获取内容异常", e);
            return JsonMessage.getString(500, "获取异常：" + e.getMessage());
        }
    }

    /**
     * 上传图片到空间中
     *
     * @param localFilePath
     * @param key
     * @return
     * @throws IOException
     */
    public static boolean upload(String localFilePath, String key) throws IOException {
        String p = SystemBean.getInstance().getEnvironment().getProperty("boot.conf");
        File file = new File(p, "qiniu_info.json");
        if (!file.exists())
            throw new RuntimeException("没有配置文件信息");
        String json = FileUtil.readToString(file);
        JSONObject jsonObject = JSON.parseObject(json);
        JSONObject images = jsonObject.getJSONObject("images");
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(Zone.zone0());
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //...生成上传凭证，然后准备上传
        String accessKey = images.getString("ak");
        String secretKey = images.getString("sk");
        String bucket = "images";
        //如果是Windows情况下，格式是 D:\\qiniu\\test.png
        //String localFilePath = "/home/qiniu/test.png";
        //默认不指定key的情况下，以文件内容的hash值作为文件名
        //String key = null;
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket);
        try {
            Response response = uploadManager.put(localFilePath, key, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
            SystemLog.LOG().info("上传成功" + putRet.key + "  " + putRet.hash);
            return true;
        } catch (QiniuException ex) {
            SystemLog.LOG(LogType.CONTROL_ERROR).error("上传异常", ex);
            return false;
        }
    }

    /**
     * 下载文件
     *
     * @param httpUrl  url
     * @param saveFile save
     * @return true 下载成功
     * @throws Exception e
     */
    public static boolean httpDownload(String httpUrl, String saveFile, boolean h404) throws Exception {
        StringBuilder urlStr = new StringBuilder();
        String strs[] = httpUrl.split("/");
        for (int i = 0; i < strs.length; i++) {
            String s = strs[i];
            String andStr = i < strs.length - 1 ? "/" : "";
            if (StringUtil.isChinese(s)) {
                urlStr.append(UrlDecode.getURLEncode(s)).append(andStr);
            } else {
                urlStr.append(s).append(andStr);
            }
        }
        httpUrl = urlStr.toString();
        if (httpUrl.startsWith("https://")) {
            return HttpClientUtils.downloadFile(httpUrl, saveFile);
        }
        FileUtil.mkdirs(saveFile);
        httpUrl = httpUrl.replace(" ", "%20");
        URL url = new URL(httpUrl);
        SystemLog.LOG().info("download  " + httpUrl + "  " + saveFile);
        try {
            int byteRead;
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestProperty("User-Agent", UAG);
            int code = conn.getResponseCode();
            if (h404) {
                if (code == 404 || code == 403)
                    return false;
            }
            if (code != 200) {
                throw new RuntimeException(httpUrl + "下载文件状态码：" + code);
            }
            InputStream inStream = conn.getInputStream();
            FileOutputStream fs = new FileOutputStream(saveFile);
            byte[] buffer = new byte[1204];
            while ((byteRead = inStream.read(buffer)) != -1) {
                fs.write(buffer, 0, byteRead);
            }
            fs.close();
            inStream.close();
            return true;
        } catch (IOException e) {
            SystemLog.LOG(LogType.CONTROL_ERROR).error("解析文件异常", e);
            return false;
        }
    }

//    public static String getTrueName(String keyName) {
//        int tryCount = 1;
//        String tempName = keyName;
//        while (true) {
//            try {
//                boolean uF = urlExists(tempName);
//                if (!uF) {
//                    tempName = String.format("%s_%s", keyName, tryCount++);
//                } else
//                    break;
//            } catch (IOException e) {
//                throw new RuntimeException(e);
//            }
//        }
//        return tempName;
//    }

    /**
     * 判断空间中是否存在对应文件
     *
     * @param keyName
     * @return
     * @throws IOException
     */
    public static boolean urlExists(String keyName) throws IOException {
        return urlExists(keyName, 0);
    }

    private static boolean urlExists(String keyName, int tryCount) throws IOException {
        try {
            String url = String.format("%s/%s", getDoMain(), keyName);
            URL hUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) hUrl.openConnection();
            return 404 == conn.getResponseCode();
        } catch (ConnectException e) {
            if (tryCount < 5)
                return urlExists(keyName, ++tryCount);
            throw e;
        }
    }

    /**
     * 获取图床空间域名
     *
     * @return
     * @throws IOException
     */
    public static String getDoMain() throws IOException {
        String p = SystemBean.getInstance().getEnvironment().getProperty("boot.conf");
        File file = new File(p, "qiniu_info.json");
        if (!file.exists())
            throw new RuntimeException("没有配置文件信息");
        String json = FileUtil.readToString(file);
        JSONObject jsonObject = JSON.parseObject(json);
        JSONObject images = jsonObject.getJSONObject("images");
        return images.getString("domain");
    }

}
